//
// Created by tcj on 2022/4/1.
//

#include "tcp_server.h"
#include "config.h"
#include "log.h"

namespace sylar{
    static sylar::ConfigVar<uint64_t>::ptr g_tcp_server_tcp_read_timout =
                sylar::Config::Lookup("tcp_server.read_timout",(uint64_t)(60*1000*2),
                                                "tcp server read timout");

    static sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("system");

    TcpServer::TcpServer(sylar::IOManager *woker,sylar::IOManager* accpet_woker)
            :m_worker(woker)
            ,m_Acceptworker(accpet_woker)
            ,m_recvTimeout(g_tcp_server_tcp_read_timout->getValue())
            ,m_name("sylar/1.0.0")
            ,m_isStop(true){
    }

    TcpServer::~TcpServer(){
        for(auto& i:m_socks){
            i->close();
        }
        m_socks.clear();
    }

    bool TcpServer::bind(sylar::Adress::ptr addr) {
        std::vector<Adress::ptr> addrs;
        std::vector<Adress::ptr> fails;
        addrs.push_back(addr);
        return bind(addrs,fails);
    }

    bool TcpServer::bind(const std::vector<Adress::ptr> &addrs,std::vector<Adress::ptr>& fails) {
        for(auto& addr:addrs){
            Socket::ptr sock = Socket::CreateTCP(addr);
            if(!sock->bind(addr)){
                SYLAR_LOG_ERROR(g_logger)<<"bind fail errno="<<errno<<" errstr="<<strerror(errno)
                            <<" addr=["<<addr->toString()<<"]";
                fails.push_back(addr);
                continue;
            }
            if(!sock->listen()){
                SYLAR_LOG_ERROR(g_logger)<<"listen fail errno="<<errno<<" errstr="<<strerror(errno)
                                         <<" addr=["<<addr->toString()<<"]";
                fails.push_back(addr);
                continue;
            }
            m_socks.push_back(sock);
        }
        if(!fails.empty()){
            m_socks.clear();
            return false;
        }

        for(auto& i: m_socks){
            SYLAR_LOG_INFO(g_logger)<<"server bind success: "<<*i;
        }
        return true;
    }

    void TcpServer::startAccept(Socket::ptr sock) {
        while(!m_isStop){
            Socket::ptr client = sock->accept();
            if(client){
                client->setRecvTimeout(m_recvTimeout);
                m_worker->schedule(std::bind(&TcpServer::handleClient,shared_from_this(),client));
            }else{
                SYLAR_LOG_ERROR(g_logger)<<"accept errno="<<errno<<" errstr="<<strerror(errno);
            }
        }
    }


    bool TcpServer::start() {
        if(!m_isStop){
            return  true;
        }
        m_isStop = false;
        for(auto& sock : m_socks){
            m_Acceptworker->schedule(std::bind(&TcpServer::startAccept,shared_from_this(),sock));
        }
        return true;
    }

    void TcpServer::stop() {
        m_isStop =true;
        auto self = shared_from_this();
        m_Acceptworker->schedule([this,self](){
           for(auto& sock:m_socks){
               sock->cancelAll();
               sock->close();
           }
           m_socks.clear();
        });
    }

    void TcpServer::handleClient(Socket::ptr client) {
        SYLAR_LOG_INFO(g_logger)<<"handleclient"<<*client;
    }

}